package com.atguigu.gmall.cart.service.impl;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.atguigu.gmall.cart.entities.CartInfo;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.Json;
import com.atguigu.gmall.common.utils.RequestUtils;
import com.atguigu.gmall.feignclients.product.SkuFeignClient;
import com.atguigu.gmall.product.entity.SkuInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    SkuFeignClient skuFeignClient;

    @Autowired
    ThreadPoolExecutor executor;

    @Override
    public String determinCartKey() {
        String cartKey = RedisConst.CART_INFO;
        Long uid = RequestUtils.uid();

        if (uid!=null){
            cartKey = cartKey + uid;
            return cartKey;
        }

        String tempid = RequestUtils.tempid();
        if (!StringUtils.isEmpty(tempid)){
            cartKey = cartKey+tempid;
        }
        return cartKey;
    }

    /**
     * 给购物车中添加商品.如果购物车之前没有这个商品就是新增.如果没有,那就是添加
     * @param skuId
     * @param skuNum
     * @param cartKey
     * @return
     */
    @Override
    public SkuInfo addItemToCart(Long skuId, Integer skuNum, String cartKey) {

        SkuInfo data = null;

        //1,以后操作redis都是String, key hasKey, hasValue
        boolean hasKey = redisTemplate.opsForHash().hasKey(cartKey, skuId.toString());
        if (!hasKey){
            //===新增不能超过两百个
            Long size = redisTemplate.opsForHash().size(cartKey);
            if (size > RedisConst.CART_ITEM_LIMIT){
                //购物车条目超限; 只要触发异常,自动抛出去
                throw new GmallException(ResultCodeEnum.CART_ITEM_OVERFLOW);
            }
            if (skuNum > RedisConst.CART_NUM_LIMIT) {
                throw new GmallException(ResultCodeEnum.CART_ITEM_NUM_OVERFLOW);
            }
            //2,购物车没有这个商品,则新增
            CartInfo cartInfo = new CartInfo();
            Result<SkuInfo> skuInfo = skuFeignClient.getSkuInfo(skuId);
            data = skuInfo.getData();
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(data.getPrice());
            cartInfo.setSkuPrice(data.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(data.getSkuDefaultImg());
            cartInfo.setSkuName(data.getSkuName());
            cartInfo.setIsChecked(1);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            //3,新增
            saveToRedis(cartKey, cartInfo);
        }
        //4,购物车有这个商品,修改数量
        CartInfo cartInfo = getCartItem(skuId, cartKey);
        cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
        if (cartInfo.getSkuNum() > RedisConst.CART_NUM_LIMIT) {
            throw new GmallException(ResultCodeEnum.CART_ITEM_NUM_OVERFLOW);
        } else {
            //4.1 保存到redis中
            saveToRedis(cartKey, cartInfo);
            String skuName = cartInfo.getSkuName();
            String imgUrl = cartInfo.getImgUrl();
            SkuInfo skuInfo = new SkuInfo();
            skuInfo.setSkuName(skuName);
            skuInfo.setSkuDefaultImg(imgUrl);
            data = skuInfo;
        }
        //5, 给临时购物车一个过期时间
        if (RequestUtils.uid() == null && !StringUtils.isEmpty(RequestUtils.tempid())) {
            //只要用了,就从最后一次使用开始计算过期时间
            Long expire = redisTemplate.getExpire(cartKey);
            //没设置过期时间就设置过期时间
            if (expire < 0){
                redisTemplate.expire(cartKey, Duration.ofDays(365));
            }
        }
        return data;
    }



    @Override
    public List<CartInfo> getCartList(String cartKey) {

        //如果是登录,要合并购物车.把临时购物车的所有商品添加到用户登录的购物车中
        Long uid = RequestUtils.uid();
        if (uid != null){
            String tempid = RequestUtils.tempid();
            //如果临时购物车有数据
            List<Object> tempJson = redisTemplate
                    .opsForHash()
                    .values(RedisConst.CART_INFO + tempid);
            if (tempJson != null && tempJson.size() > 0) {
                tempJson.stream().forEach(item->{
                    CartInfo info = Json.Obj(item.toString(), CartInfo.class);
                    addItemToCart(info.getSkuId(), info.getSkuNum(), cartKey);
                });
                //删除临时购物车数据
                redisTemplate.delete(RedisConst.CART_INFO + tempid);
            }
        }

        List<Object> values = redisTemplate.opsForHash().values(cartKey);
        List<CartInfo> cartInfos = values
                .stream()
                .map(item -> Json.Obj(item.toString(), CartInfo.class))
                .sorted((o1,o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                .collect(Collectors.toList());

        CompletableFuture.runAsync(()->{
            this.batchUpdatePrice(cartKey, cartInfos);
        }, executor);

        return cartInfos;
    }

    @Override
    public void updateCartStatus(String cartKey, Long skuId, Integer status) {
        CartInfo cartInfo = getCartItem(skuId, cartKey);
        cartInfo.setIsChecked(status);

        //保存到redis中
        saveToRedis(cartKey, cartInfo);
    }



    @Override
    public void updateCartItemCount(String cartKey, Long skuId, Integer num) {
        CartInfo cartItem = getCartItem(skuId, cartKey);
        cartItem.setSkuNum(cartItem.getSkuNum() + num);

        //保存到redis中
        saveToRedis(cartKey, cartItem);
    }

    //删除购物车
    @Override
    public void deleteCartItem(String cartKey, Long skuId) {
        redisTemplate.opsForHash().delete(cartKey, skuId.toString());
    }

    //删除选中商品
    @Override
    public void deleteChecked(String cartKey) {
        List<CartInfo> cartList = getCartList(cartKey);
        List<String> skuIds = cartList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                .map(cartInfo -> cartInfo.getSkuId().toString())
                .collect(Collectors.toList());

        if (skuIds!=null && skuIds.size()>0){
            redisTemplate.opsForHash().delete(cartKey, skuIds.toArray());
        }
    }

    @Override
    public void batchUpdatePrice(String cartKey, List<CartInfo> cartInfos) {
        List<CartInfo> cartList = cartInfos;

        cartList.stream().forEach(item -> {
            Result<BigDecimal> skuPrice = skuFeignClient.getSkuPrice(item.getSkuId());

            if (!(skuPrice.getData().subtract(item.getSkuPrice()).doubleValue() < 0.001)) {
                item.setSkuPrice(skuPrice.getData());
                //item.setSkuPrice
                item.setSkuPrice(skuPrice.getData());
                saveToRedis(cartKey, item);
            }

        });
    }

    //获取购物车对象
    private CartInfo getCartItem(Long skuId, String cartKey) {
        //4.1拿到这个购物车这个商品
        String json = (String)redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //4.2,逆转成我们能用的对象
        CartInfo cartInfo = Json.Obj(json,CartInfo.class);
        return cartInfo;
    }

    //保存到redis
    private void saveToRedis(String cartKey, CartInfo cartInfo) {
        if (cartInfo.getSkuNum() > RedisConst.CART_NUM_LIMIT) {
            throw new GmallException(ResultCodeEnum.CART_ITEM_NUM_OVERFLOW);
        }
        redisTemplate.opsForHash().put(cartKey, cartInfo.getSkuId().toString(), Json.toJsonStr(cartInfo));
    }

}
